<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.17"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>My Project: Project</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
  $(document).ready(function() { init_search(); });
/* @license-end */
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">My Project
   </div>
  </td>
   <td>        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="Search" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
</td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.17 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(document).ready(function(){initNavTree('md_note.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="PageDoc"><div class="header">
  <div class="headertitle">
<div class="title">Project </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><blockquote class="doxtable">
<p>王耕宇 孙姝然 盛钺 </p>
</blockquote>
<p>检查点1到期：2022.11.20</p>
<p>检查点2到期：2022.12.18</p>
<hr  />
<p>项目分为两个检查点。</p>
<ul>
<li>实现一个基于网络通信的微型FTP客户端和服务器</li>
<li>更进一步，实现TCP协议</li>
</ul>
<p>[toc]</p>
<h1><a class="anchor" id="autotoc_md4"></a>
检查点1</h1>
<p>写一个使用文件传输协议（FTP）子集的简单客户端和服务器，严格按照RFC实现这一协议。使用者使用明文验证来登录协议，通常是用户名、密码的形式，但是如果配置了服务器，可以允许匿名连接。</p>
<p>实现FTP客户端/服务器，基于C语言，使用TCP协议实现下载/上传。要求控制和数据链接使用分离。</p>
<p>FTP服务器用来存储文件，用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的文件资源。</p>
<h2><a class="anchor" id="autotoc_md5"></a>
1. 命令</h2>
<p>需要实现的命令如下：</p>
<blockquote class="doxtable">
<p>get [remote-filename]</p>
<p>put [local-filename]</p>
<p>delete [remote-filename]</p>
<p>ls</p>
<p>cd [remote-directory-name] or cd ..</p>
<p>mkdir [remote-directory-name]</p>
<p>pwd</p>
<p>quit </p>
</blockquote>
<h2><a class="anchor" id="autotoc_md6"></a>
2. 要求</h2>
<ol type="1">
<li>实现两种FTP传输方法</li>
</ol>
<ul>
<li>ASCII代码</li>
<li>二进制</li>
</ul>
<p>假设客户端复制了一个包含简单的ASCII文本的文件，这种情况下，FTP自动调整文件内容来方便将文件解释为存储在服务器上的文件格式。</p>
<p>如果文件中不仅包含ASCII文本，如程序、数据库、字处理文件或压缩文件。这种情况下应使用二进制传输模式来保存文件的位顺序，以便原始文件和复制的文件都是bit by bit</p>
<ol type="1">
<li>允许实施合理的异常处理方案，例如用户非法输入时提供适当的错误提示，来保证程序的健壮性。</li>
<li>自行设计实验中没有解释清楚的细节</li>
</ol>
<h2><a class="anchor" id="autotoc_md7"></a>
3. 提交</h2>
<p>组长负责提交三份材料。</p>
<ul>
<li>代码：“组长学号-组长姓名-代码.zip”</li>
<li>代码文档：“组长学号-组长姓名.pdf”</li>
<li>一个视频，解释实现的关键思想以及实际运行效果："组长学号-组长姓名-视频.zip"</li>
</ul>
<p>代码文档需要包含编程思想，关键代码分析，每个函数的运行效果的屏幕截图，以及团队劳动贡献清单</p>
<p><img src="C:\Users\98157\AppData\Roaming\Typora\typora-user-images\image-20221025135522316.png" alt="image-20221025135522316" class="inline"/></p>
<p>会选择一些小组进行现场或在线面对面测试。根据以下方面评分</p>
<ul>
<li>命令的实现</li>
<li>程序健壮性</li>
<li>代码编写质量</li>
<li>文档质量</li>
<li>团队贡献和努力</li>
</ul>
<h2><a class="anchor" id="autotoc_md8"></a>
4. 示例</h2>
<p>客户端根目录有一个名为test.txt的文件，客户端通过put命令上传该文件。</p>
<p>执行命令后，文件上传到服务器端</p>
<p><img src="C:\Users\98157\AppData\Roaming\Typora\typora-user-images\image-20221025135822165.png" alt="image-20221025135822165" class="inline"/></p>
<h2><a class="anchor" id="autotoc_md9"></a>
5. 测试</h2>
<p>使用以下命令测试实现，需要执行相同的测试并将测试结果添加进文档</p>
<ol type="1">
<li>启动客户端和服务器，并建立连接</li>
<li>mkdir A | 在服务器的根目录创建一个目录A。</li>
<li>cd A | 将工作目录更改为A。</li>
<li>mkdir B | 创建目录B</li>
<li>cd B</li>
<li>pwd</li>
<li>put test.txt | 上传一个文件</li>
<li>ls | 列出B中文件</li>
<li>cd .. | 将目录更改为A</li>
<li>pwd</li>
<li>cd B</li>
<li>get test.txt</li>
<li>delet test.txt</li>
<li>ls</li>
<li>get test.txt</li>
<li>quit</li>
</ol>
<h1><a class="anchor" id="autotoc_md10"></a>
检查点2</h1>
<p>TCP是一层传输层协议，使不同设备上的进程能够可靠地进行通信。T最大努力传输意味着数据包可能丢失、复制、重新排序，并不能保证可用带宽保持不变（网路本身变化或者其它流量干扰）</p>
<p>TCP应向程序保证数据将按顺序交付，未损坏，并且传输将减缓来避免拥塞控制（网络）或者流量控制（连接终端）。TCP还应保证公平，试图给予平等的带宽份额到同一链接的多个发送者</p>
<p>实现TCP，过程中应关注TCP Reno这一算法。这一算法一直在发展，是众多拥塞控制算法（CCAs）之一。公司给予上下文环境使用不同的CCAs。例如，一个版本在数据中心内部是合适的，而另一个版本可能适用于因特网上的网页提供服务。对于Web内容，最常用的算法是Cubic。Akamai是世界上最大的内容分发网络，以FastTCP命名。</p>
<p>通过这部分内容，你将获得以下经验</p>
<ul>
<li>使用低级语言（C）构建非平凡的计算机系统</li>
<li>构建在互联网上使用的可互操作程序</li>
<li>底层网络不可靠背景下设计端到端系统</li>
<li>分析算法的性能，设计改进这些指标的方法，并测试这些改进</li>
</ul>
<p>在这个检查点中，需要实现TCP三向握手、RTT评估以及TCP的滑动窗口算法</p>
<h2><a class="anchor" id="autotoc_md11"></a>
1. CMU-TCP</h2>
<p><img src="E:\Blood\thirdyear_autumn\操作系统(H)\LAB\lab5\image-20221025141608671.png" alt="image-20221025141608671" class="inline"/></p>
<p>CMU-TCP是一个简单可靠的传输协议，与传统TCP实现不同，CMU-TCP段被UDP有效载荷携带，这使你可以使用UDP socket实现CMU-TCP并受益于UDP现有的多路复用/解复用功能。与传统TCP一样，CMU-TCP连接两个端点，发起方和监听器。虽然CMU-TCP表头与传统TCP贡献多个字段，但结构还是不同的：</p>
<ul>
<li>Identifier : 标识符，所有CMU-TCP数据包都必须设置为15441的标识符开头</li>
<li>Source Port : 源端口，与头部中的UDP源端口匹配</li>
<li>Destination Port : 目标端口，与头部中的UDP目标端口匹配</li>
<li>Sequence Number : 此段中第一字节的序列号，除非设置SYN，否则这个数字是初始序列号（ISN），发送的一个数据将以ISN+1作为序列号</li>
<li>Acknowledgment Number : 确认编号，在设置ACK标志时有效，标识发送者期望的下一序列号</li>
<li>Header Length : CMU-TCP的头长度（单位byte，25字节，无扩展数据）</li>
<li>Packet Length : CMU-TCP数据包长度（单位byte，有效载荷+头部）</li>
<li>Flags : 使用8位中的3位，从0开始从左到右<ul>
<li>SYN (bit 4): 同步序列号，连接开始时双方使用</li>
<li>ACK (bit 5): 确认数，重要</li>
<li>FIN (bit 6): 发送发没有要发送的数据</li>
</ul>
</li>
<li>Advertised Window : 广告窗口，发送方在其窗口中可接受的字节数</li>
<li>Extension Length : 扩展数据字段的长度（单位byte）</li>
<li>Extension Data : 任意的扩展数据，可以在开发自己的CCA时使用它。</li>
</ul>
<p>作为开始，你将收到使用停止等待传输实现的CMU-TCP起始代码。但是停止等待效率非常低，它只为每个PTT传输一个数据报。这个起始代码还缺少连接设置和终止、拥塞控制、流量控制。在这一检查点中，你应该使用握手和窗口机制扩充起始代码，以便在下一个ACK之前发送到达多个数据包。这一窗口在编译过程中恢复。你也需要实施RTT估计，以便能够更有效地从损失中恢复。</p>
<p>可选的，你还可以实现连接终止以赢得奖励积分。</p>
<p>这一检查点要求运行一些experiments来运行假设，应确保尽早实现以便有时间进行实验。</p>
<p>你将使用UDP socket实现CMU-TCP，自行制作数据报并传送，UDP不会重新传输丢失的数据报，UDP无法控制数据报的发送时间，即发送吞吐量。你必须扩充UDP以实现这些特性。由于发起方和监听方都可以发送和接收，因此你需要跟踪大量的数据和信息。重要的是写下在你实现时的每一方知道的everything并利用接口保持代码的模块化和可用性。实施TCP的指南可以在5.2和6.3节找到。开始之前请阅读这一部分</p>
<h2><a class="anchor" id="autotoc_md12"></a>
2. 开始代码和实现细节</h2>
<p>The starter code is hosted on GitHub: <a href="https://github.com/17ssDP/cmu-tcp">https://github.com/17ssDP/cmu-tcp</a> . See README.md for a description of the files in the starter code and instructions on how to run it.</p>
<p>暴露给应用的API写在<code>cmu_tcp.h</code>，包含四个核心函数，函数不可更改：<code>cmu_socket</code>, <code>cmu_close</code>, <code>cmu_read</code>, and <code>cmu_write</code>，通过调用cmu_socket，应用程序需要请求新的CMU-TCP socket，应用程序指定其是监听器（如服务器）还是启动器（如客户端）。对于监听器 socket，应邀程序要制定监听的端口。对于启动器socket，应用程序要指定监听器的IP和端口号。</p>
<p>初始化socket后，应用程序可以使用<code>cmu_write</code>传输数据，<code>cmu_read</code>接收数据，<code>cmu_read</code>还接收flags，来定义没有数据读取货返回的情况下是否应该立即阻塞，或者无数据立即返回，当应用程序发送数据完成后，需要调用cmu_close终止socket。</p>
<p>虽然 API 中定义的函数是在 cmu_tcp.c 中实现的，该函数与应用程序运行在同一线程，但是CMU-TCP 的大多数核心逻辑实际上都在单独的后端线程中运行。这很重要，因为 TCP 必须能够独立于应用程序工作（例如，接收、确认和重新传输数据包）。因此，在cmu_tcp.c中实现的逻辑只是负责与后端线程和进行通信，你的大多数实现都应该写在&lt;tt&gt;backend.c。</p>
<p>起始代码还包括两个使用 CMU-TCP 进行通信的示例应用程序（server.c 和client.c）。你可以使用并调整这些应用程序来测试我们的代码。我们还提供用Python编写的简单自动测试， 您可以在此基础上实现更精细的测试。</p>
<p>我们将使用<code>grading.h</code>来帮助我们测试你的代码。我们会调整文件中变量的值确保你不是在某个地方硬编码。比如我们会改变包长度和初始窗口变量。</p>
<p>所有多字节整数字段必须按网络字节顺序传输。<code>ntoh()</code>、<code>hton()</code> 和类似的函数是重要的。我们还提供了许多辅助函数来获取和设置不同的数据包字段，自动处理字节序。请参考<code>cmu_packet.h</code>中的签名和<code>cmu_packet.h</code>中的实现。你必须在比较序列号时要小心，因为它们可能会wrap around。在比较序列号时，您可以使用<code>cmu_packet.h</code> 中提供的辅助函数之一（before、after、between）。您还应该确保IDENTIFIER始终被设置为 15441，即使您采用 15-641（脚本依赖于此）。不允许更改头部的结构。数据包长度 （plen） 不能超过 MAX_LEN以防止数据包被分解成零件。</p>
<p>您可以使用窃听（Wireshark）或tcpdump（2.4.3 节）验证您的头部是否正确发送，其允许您检查数据包中的数据，包括完整的以太网帧。查看数据包时，您应该会看到类似于下图的情况，在这种情况下，有效负载从0x0020开始。IDENTIFIER（15441） 以十六进制显示为0x00003C51。</p>
<p><img src="C:\Users\98157\AppData\Roaming\Typora\typora-user-images\image-20221025150307532.png" alt="image-20221025150307532" class="inline"/></p>
<h2><a class="anchor" id="autotoc_md13"></a>
3. 评估</h2>
<p>您对此检查点的评分将基于两个组件：</p>
<ul>
<li>一个实现组件，其通过手动评估以及Gradescope上的一套自动化测试用例</li>
<li>一个测试组件，在这里，你将假设、试验和回答与CMU-TCP实现有关的问题。</li>
</ul>
<p>请注意，实现和测试组件具有相同的权重。你应该尽早实施以有时间进行实验并撰写报告。</p>
<p>因此，您需要提交与CP1相同的材料：源代码，包含答案的PDF答案和一个视频</p>
<h2><a class="anchor" id="autotoc_md14"></a>
4. 概述</h2>
<p>您的实现应该：</p>
<ol type="1">
<li>执行 TCP 三次握手 [3]。</li>
<li>随机初始化序列号，并在握手期间同步它们。</li>
<li>使用RTT估计：您会注意到损失恢复非常缓慢！其中一个原因是起始代码使用固定的重传超时 （RTO） 为 3 秒。通过使用Jacobson/Karels和Karn/Partridge 任一算法评估RTT 来实现自适应RTO。</li>
<li>使用固定窗口大小在 ACK 之前传输多个数据包（必须将窗口大小设置为WINDOW_INITIAL_WINDOW_SIZE 字节）。</li>
<li>[可选] 执行连接拆卸 [3]。</li>
</ol>
<p>您应该使用提供的脚本（prepare_submission.sh）创建存档（handin.tar.gz）。 在运行脚本之前，确保所有与提交相关的文件已被提交。然后，您可以将此存档提交给Gradescope。您的实现将使用以下评分标准自动评分：</p>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">类型 </th><th class="markdownTableHeadNone">权重 </th><th class="markdownTableHeadNone">标准  </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">启动器握手 </td><td class="markdownTableBodyNone">20% </td><td class="markdownTableBodyNone">- 正确发送第一个 SYN 数据包<br  />
- 拒绝来自侦听器的格式错误的 SYN-ACK 数据包<br  />
- 握手完成后正确接收数据包<br  />
  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">监听器握手 </td><td class="markdownTableBodyNone">30% </td><td class="markdownTableBodyNone">- 不响应无效的 SYN 数据包<br  />
- 使用有效的合成确认数据包响应有效的合成数据包<br  />
- 丢失时重新传输合成确认数据包<br  />
- 在合成确认后正确处理无效的确认数据包<br  />
- 握手完成后正确接收数据包  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">可靠性 </td><td class="markdownTableBodyNone">30% </td><td class="markdownTableBodyNone">- 超时时重新传输数据包<br  />
- 在 1–3 个估计 RTT 内重新传输数据包<br  />
- 在无损条件下可靠地传输文件<br  />
- 在有损条件下可靠地传输文件  </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">窗口、序列号 </td><td class="markdownTableBodyNone">25% </td><td class="markdownTableBodyNone">- 发送方一次传输多个数据包<br  />
- 启动器正确同步序列号<br  />
- 监听器正确同步序列号<br  />
- 启动器随机初始化序列号<br  />
- 监听器随机初始化序列号  </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">拆解 </td><td class="markdownTableBodyNone">5% </td><td class="markdownTableBodyNone">- 正确发送 FIN 数据包<br  />
- 在收到 FIN-确认后发送有效的确认数据包<br  />
- 超时时重新传输 FIN 数据包<br  />
- 一方仍可在另一方启动后发送数据  </td></tr>
</table>
<h2><a class="anchor" id="autotoc_md15"></a>
5. 实验部分</h2>
<p>对于实验部分，您将测量“流完成时间”（或“FCT”：完成传输文件所需的时间）在不同丢失率（0，0.1和0.01）下。您应将基本速率固定为 10 Mbps，并设置延迟为 20 毫秒。将这些设置同时应用于服务器和客户端。对于每个不同的损失率，您将传输大小范围为：512 字节、4 KiB、32 KiB、256 KiB 和 2 MiB的文件。因此，您将测量总共15个方案：五种不同的文件大小× 三个损失率。</p>
<p>请创建包含实验报告的 PDF，并将其提交给Gradescope，并附上以下信息。</p>
<h3><a class="anchor" id="autotoc_md16"></a>
**假设**。</h3>
<p>给定起始代码（基线）中的实现和完整的 CP2 实现，在运行任何实验之前，我们要求您假设您的预期结果。</p>
<p>（1）推导一个方程来预测初始实现需要多长时间（以RTT的数量为单位）来转移大小𝑓 损失率𝑝的文件。回想一下，吞吐量是固定的（10 Mbps），RTT也固定在40毫秒（每端20毫秒延迟）。</p>
<p>（2） 推导一个等式来预测 CP2 的实现传输大小𝑓 损失率𝑝的文件需要多长时间（以 RTT 的数量为单位）（不要忘记握手，如果你实现了它，拆解时间！）</p>
<p>（3） 使用这两个等式，预测您的 CP2 实现在哪些情况下会优于基线。</p>
<p>同样，预测基线实现何时会优于 CP2 实现。提供图表，其中包含每个测试方案的条目，用于预测使用基线或你的新的实现完成文件传输所需的 RTT 数。</p>
<h3><a class="anchor" id="autotoc_md17"></a>
&lt;strong&gt;实验。&lt;/strong&gt;</h3>
<p>在您用于开发代码的Vagrant汉环境中，测量传输不同文件大小和不同损耗比所需的时间：512 字节、4 千字节、32 千字节、256 千字节和 2 MiB，不同损耗比：0、0.1和0.01% 。所有器件的基本速率均为 10 Mbps，RTT 为 40 ms（每侧配置 20 ms 延迟）。参考（section 2.4.2）如何人为设置损耗比、吞吐量和延迟的说明。重复基线实现以及 CP2 实现的实验。对于CP2实验，传输过程应包括握手，如果您实现了握手，则应包括拆解时间。</p>
<p>为每个损失比率创建单独的条形图（3 个图）。在每个图中，指示传输大小为𝑥 轴和传输持续时间（以毫秒为单位）为𝑦 轴。每个传输大小应该有四个条形：一个带有传输的条形是基线实现的持续时间，一个具有给定方程（1）的预测持续时间，另一个是CP2 实现的传输持续时间，以及给定等式（2）预测的传输持续时间。对于你的测量结果，每个柱应指示 10 次运行的中位数（即，您应该在相同条件下重复相同的传输 10次，并报告中位数）。您还应该通过误差条形柱报告每个数据点的标准偏差。确保在两个轴中标记并包含该单元，并包含图例以标识条形图。</p>
<h3><a class="anchor" id="autotoc_md18"></a>
&lt;strong&gt;推理。&lt;/strong&gt;</h3>
<p>根据实验结果，我们要求您回答以下问题：</p>
<ul>
<li>您的等式（1）与基线实现的实际结果的匹配程度如何？提供一些关于两者之间差距的根源是什么的想法，以及你如何改进你的等式。</li>
<li>您的等式 （2） 与基线实现的实际结果的匹配程度如何？提供一些关于两者之间差距的根源是什么的想法，以及你如何改进你的等式。</li>
<li>你对基线或CP2的预测的准确性如何？对于给定的场景，实现会表现得更好吗？如果您的预测曾经有误，请</li>
</ul>
<p>假设为什么你的预测是错误的。</p>
<h2><a class="anchor" id="autotoc_md19"></a>
6. 资源</h2>
<p>本节介绍一些用于开发和测试 CMU-TCP 的推荐工具</p>
<h3><a class="anchor" id="autotoc_md20"></a>
1. 开发环境</h3>
<p>对于次检查点，可以使用容器在自己计算机上执行所有开发。如果想要更方便，欢迎继续使用AWS进行开发。按照你的选择，你应该安装Docker或Vagrant在计算机上，我们提供了一个Vagrant文件，指定两个容器，一个客户端和一个服务器。Vagrant文件配置为将存储库的目录映射到容器的<code>/Vagrant/</code>目录。这表示你对此目录所做的任何更改都将传播到其他地方，你可以通过运行<code>vagrant up --provider=docker from the cmu-tcp directory</code>来构建和启动容器。你可以使用Vagrant登录两个容器中的任何一个ssh {客户端|服务器}。服务器和客户端通过虚拟网络连接，IP 地址为 10.0.1.1 和 10.0.1.2。但请注意，即使这些 IP 地址发生更改，您的代码也应该有效。</p>
<p>以下各节介绍容器上已安装的工具，可帮助您测试代码。你还可以安装您需要的任何其他工具。</p>
<h3><a class="anchor" id="autotoc_md21"></a>
2. 使用 tc 配置控制网络特性</h3>
<p>tcconfig安装在容器上，让你人为地控制连接到容器的虚拟网络的特征。容器上的初始默认设置是每个容器 20 毫秒延迟（因此总 RTT 为 40 毫秒），双向带宽为 100 Mbps，无损耗。在容器上运行 <code>tcshow $IFNAME</code>，将显示这些设置。您可以使用 tcset 设置其他 tc 参数，例如<code>sudo tcset $IFNAME -- rate 10Mbps --delay 20ms --loss 0.1% --overwrite</code>，有关如何使用 tcconfig 模拟将用于测试代码，包括数据包丢失、重新排序和损坏的不同网络特征的更多信息，请参阅参考资料 。</p>
<h3><a class="anchor" id="autotoc_md22"></a>
3. 使用tcpdump 和 tshark 捕获和分析数据包</h3>
<p>tcpdump和Wireshark（及其等效的命令行程序：tshark）安装在容器上，允许您捕获在容器之间发送的数据包并在以后对其进行分析。我们在目录项目-2_15-441-2/utils/ 来帮助进行数据包分析（如果需要，可以随意修改这些）：</p>
<ul>
<li>capture_packets.sh：这是一个简单的程序，显示如何启动和停止数据包捕获以及使用tshark分析数据包。start 函数在后台启动数据包捕获。停止功能停止数据包捕获。最后，分析函数将使用 tshark 输出一个 CSV 文件，其中包含 TCP 中的头部信息。有关示例，请参见第 2.4.4 节。</li>
<li>tcp.lua：这是一个Lua插件，以便窃听器可以剖析我们的自定义CMU-TCP数据包格式。capture_packets.sh显示了如何将此文件传递给 tshark 以解析数据包。要使用包含Wireshark GUI的插件，您应该将此文件添加到Wireshark的plugin文件夹。</li>
</ul>
<h3><a class="anchor" id="autotoc_md23"></a>
4. 分析大型文件传输</h3>
<p>起始代码client.c 和server.c 将在客户端和服务器之间传输一个小文件cmu_tcp.c。你应该通过传输大文件、捕获数据包和绘制随时间变化的拥塞窗口来测试代码。</p>
<p>您可以通过运行以下命令使用上一节中描述的实用程序来创建 capture.pcap 和 graph.pdf，</p>
<p>命令：</p>
<p>在服务器容器，启动tcpdunmp和server</p>
<div class="fragment"><div class="line">vagrant@server:/vagrant/project-2_15-441-2$ make</div>
<div class="line">vagrant@server:/vagrant/project-2_15-441-2$ ./utils/capture_packets.sh start capture.pcap</div>
<div class="line">vagrant@server:/vagrant/project-2_15-441-2$ ./server</div>
</div><!-- fragment --><p>在客户端容器，启动客户端</p>
<div class="fragment"><div class="line">vagrant@client:/vagrant/project-2_15-441-2$ ./client</div>
<div class="line">vagrant@server:/vagrant/project-2_15-441-2$ ./utils/capture_packets.sh stop capture.pcap</div>
<div class="line">vagrant@server:/vagrant/project-2_15-441-2$ ./gen_graph.py</div>
</div><!-- fragment --><h3><a class="anchor" id="autotoc_md24"></a>
5. 使用 pytest 运行测试</h3>
<p>可以通过多种方式为代码编写测试。为了帮助您入门，pytest安装在容器，我们在测试/test_cp1.py中提供了一些基本测试的示例。运行 make 测试将运行这些测试。你应该扩展这些测试或使用其他工具测试代码。但是，请务必更新Makefile以便每次必须运行测试。与检查点 1 一样，您还应该使用标准 C 调试工具，包括gdb和Valgrind，它们也安装在容器上。</p>
<h3><a class="anchor" id="autotoc_md25"></a>
6. 自动代码格式化和分析</h3>
<p>我们提供了一个预提交配置文件，无论什么时候你在一个容器中运行make format，你都可以使用该文件自动格式化和静态检查您的代码。您可以选中 .pre-commit-config .yaml 以查看我们运行的全部钩子。您也可以选择将其安装在开发计算机中。每当您创建新提交时，都将确保运行所有钩子。如果要在本地计算机中安装pre-commit，请运行pip3 install pre-commit。然后在 cmu-tcp 存储库的根目录中运行 pre-commit install以安装预提交钩子。</p>
<h2><a class="anchor" id="autotoc_md26"></a>
7. 其他</h2>
<h3><a class="anchor" id="autotoc_md27"></a>
起始代码。</h3>
<p>我们保留在项目进行过程中更改起始代码以修复错误和引入的权利，帮助您调试代码的新功能（我们承诺使更改尽可能透明，以免破坏您的工作实现）。您有责任查看在线学习/微信以保持最新状态的变化。我们将假设班上的所有学生都会阅读并了解发布的任何信息。</p>
<h3><a class="anchor" id="autotoc_md28"></a>
重用代码。</h3>
<p>您可以使用以前编写的任何代码（例如，从15-213/513，黑客马拉松， 等），但您不得使用来自任何人或其他任何地方的代码。欢迎您克隆项目存储库以留下来最新的更改（例如，错误修复），但请不要将您的解决方案代码推送到公共分支。学术诚信违规行为非常严重，您将与与您一样与某人共享代码负责。</p>
<h3><a class="anchor" id="autotoc_md29"></a>
测试。</h3>
<p>入门代码包括一套公共测试用例，可帮助您入门，但自动评分器可能会使用用于对解决方案进行分级的私有测试用例（不过，您将在提交时看到最终分数）。请运行你自己的测试：从长远来看，它将为您和您的组员节省很多调试痛苦！ </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="footer">Generated by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.17 </li>
  </ul>
</div>
</body>
</html>
